﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using CoffeePotServer;
using System.Threading;
namespace Client
{
    /// <summary>
    /// File: Client_Handler.cs
    /// Author: James Dibble 10009689, Harry Winser 10016143
    /// Last Revision: 20/03/12
    /// </summary>
    class HTCPCPClient
    {
        #region Attributes
        private static Boolean _bolDebug = true;
        private Socket _sktClient;
        private NetworkStream _netStream;
        private Socket_Reading _serverResponse;
        private Socket_Sending _clientResponse;
        private ClientRequest _initialRequest;
        private String _strLastMessage;
        #endregion

        #region Constructor
        /// <summary>
        /// A HTCPCP Client
        /// </summary>
        /// <param name="Request">Input URL</param>
        public HTCPCPClient(ClientRequest Request)
        {
            _initialRequest = Request;
            _sktClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _sktClient.Connect(Request.Host, Request.Port);
            _netStream = new NetworkStream(_sktClient);
            _serverResponse = new Socket_Reading(_netStream, _sktClient);
            _clientResponse = new Socket_Sending(_netStream);
            FulfillRequest();
        }
        /// <summary>
        /// A HTCPCP Client
        /// </summary>
        /// <param name="Request">Input URL</param>
        /// <param name="Port">Port Number</param>
        public HTCPCPClient(ClientRequest Request, String Port)
        {
            _initialRequest = Request;
            _sktClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _sktClient.Connect(Request.Host, Convert.ToInt32(Port));
            _netStream = new NetworkStream(_sktClient);
            _serverResponse = new Socket_Reading(_netStream, _sktClient);
            _clientResponse = new Socket_Sending(_netStream);
            FulfillRequest();
        }
        #endregion

        #region Properties
        /// <summary>
        /// Debug Mode On or Off
        /// </summary>
        public static Boolean DebugMode
        {
            get { return _bolDebug; }
            set { _bolDebug = value; }
        }
        #endregion

        #region Methods
        /// <summary>
        ///Executes the Protocol
        /// </summary>
        private void FulfillRequest()
        {
            if (_initialRequest.Pot == "" && _initialRequest.Additions == null) // create PROPFIND message
            {
                Console.WriteLine("Sending Propfind...");
                _clientResponse.SendLine(new ClientMessage().BuildMessage(ClientMessage.MethodType.PROPFIND,
                                                                          _initialRequest.Pot));
                ServerResponse response = new ServerResponse(_serverResponse.ReadLine());// read response from server
                Console.WriteLine(response.AdditionalMessage);
            }
            else
            {
                Console.WriteLine("Brewing on {0}...", _initialRequest.Host);
                _clientResponse.SendLine(new ClientMessage().BuildMessage(ClientMessage.MethodType.GET, // create Get and Send, to get state of Server 
                                                                          _initialRequest.Pot));
                ServerResponse response = new ServerResponse(_serverResponse.ReadLine());
                if (DebugMode) Console.WriteLine(response.ToString());
                if (response.Code.Trim() == "200" || response.Code.Trim() == "419") // accepted
                {
                    if (_initialRequest.Additions.Length == 0)
                        _clientResponse.SendLine(new ClientMessage().BuildMessage(ClientMessage.MethodType.BREW,
                                                                                  _initialRequest.Pot)); // create Brew without additions
                    else
                        _clientResponse.SendLine(new ClientMessage().BuildMessage(_initialRequest.Pot,
                                                                                  _initialRequest.Additions)); // creates Brew with addtions
                    response = new ServerResponse(_serverResponse.ReadLine());
                    if (response.Code.Trim() == "200" || response.Code.Trim() == "202") //request has been accepted
                    {
                        Boolean bolLoop = true;
                        while (bolLoop) //  until the coffee pot has boiled
                        {
                            _clientResponse.SendLine(new ClientMessage().BuildMessage(ClientMessage.MethodType.GET,
                                                                                      _initialRequest.Pot, true));
                            response = new ServerResponse(_serverResponse.ReadLine());
                            if (response.Code.Trim() == "200" || response.Code.Trim() == "202") bolLoop = false;
                            else if (response.Code.Trim() == "505") bolLoop = true;
                            else throw new ClientException("Coffee could not be brewed.", ClientException.ExceptionType.NOCOFFEE);
                            Thread.Sleep(1000);
                        }
                        if (_initialRequest.Additions == null) // no additions
                        {
                            Console.WriteLine("Your Coffee is ready.");
                            Console.ReadLine();
                        }
                        else
                        {
                            foreach (String strAddition in _initialRequest.Additions) // if there are addtions to the coffee
                            {
                                Console.WriteLine("Adding {0}", strAddition);
                                Thread.Sleep(2000);
                                _clientResponse.SendLine(new ClientMessage().BuildMessage(ClientMessage.MethodType.WHEN,
                                                                              _initialRequest.Pot)); // create WHERN after period of time
                            }
                            _clientResponse.SendLine(new ClientMessage().BuildMessage(ClientMessage.MethodType.GET,
                                                                                      _initialRequest.Pot)); // gets final coffee
                            response = new ServerResponse(_serverResponse.ReadLine());
                            if (response.Code == "200") Console.WriteLine("Your coffee is ready.");
                            else Console.WriteLine("There was an error brewing your coffee.");
                            Console.ReadLine();
                        }
                    }
                    else
                    {
                        Console.WriteLine("Pot is unavailable. {0}", response.Message);
                        _netStream.Close();
                    }
                }
                else
                {
                    Console.WriteLine("Pot is unavailable. {0}", response.Message);
                    _netStream.Close();
                }
            }

        }
        #endregion

   
    }
}
